#include <stdio.h>
#include <string.h>
#include <assert.h>
#include "int_expr.h"
#include "int_exec.h"
#ifdef WIN32
#include <windows.h>
#include "def_for_win.h"
#else
#include <unistd.h>
#endif /* WIN32*/
#include "logo_lib_p.h"

extern i_exec_t* g_exec;
int g_break_continue_line_no = -1;

static int ProcessDebugCommand(rte_t* rte, tree_node_t* stmt);
static int CheckForDebugStepTo(rte_t* rte, int lineno);
static int CheckForDebugGo(rte_t* rte, tree_node_t* stmt);
static int CheckForDebugStepOver(rte_t* rte, int lineno);
static int CheckForDebugStepInto(rte_t* rte, tree_node_t* stmt);
static int CheckForDebugStepOut(rte_t* rte, int lineno);

int exec_stmt_seq (rte_t* rte, tree_node_t* seq, value_t* result)
{
   tree_node_t* cur;

   if (!seq) {
      /* might be empty compound statement*/
      return 0;
   }

   assert (seq);
   assert (rte);
   assert (rte->rtn_lst);

   cur = seq;
   while (cur) {
      int ret;
      assert (cur->node_type == StmtNode);
      ret = exec_stmt (rte, cur, result);
      if (ret != 0) {
         // returned from a RETURN statement or error
         return ret;
      }
      cur = cur->sibling;
   }
   return 0;
}


#define DEBUG_CMD_INFO(command,value) \
         do { \
            print_info (DEBUG_INFO,"DEBUG, %s ", command); \
            print_value (value);  \
            print_info (DEBUG_INFO,".\r\n");   \
         } while (0) 

#define DEBUG_WAIT  0
#define DEBUG_GO    1

static int breakpoint_wait(rte_t* rte, int lineno)
{
   assert (rte);
   assert (rte->exec);

   (rte->exec)->debug_cmd_ack(lineno);
   rte->control.DbgCtrl.waitfornext = true;
   rte->control.DbgCtrl.executed = false;
   return DEBUG_WAIT;
}

static int breakpoint_go(rte_t* rte)
{
   assert (rte);
   assert (rte->exec);

   rte->control.DbgCtrl.executed = true;
   rte->control.DbgCtrl.waitfornext = false;
   return DEBUG_GO;
}

static int CheckForDebugGo(rte_t* rte, tree_node_t* stmt )
{
   assert (rte);
   assert (stmt);
   if (debug_find_breakpoint(rte, stmt->line_no) && (stmt->type.stmt != COMPOUND_STMT)) {
      return breakpoint_wait(rte, stmt->line_no); 
   }
   return breakpoint_go(rte);
}

static int CheckForDebugStepTo(rte_t* rte, int lineno)
{
   assert (rte);

   if ( (unsigned int) lineno == rte->control.DbgCtrl.lineno) {
      return breakpoint_wait(rte, lineno);
   }
   
   if (!debug_find_breakpoint(rte, lineno)) {
      return breakpoint_go(rte);
   }

   if (lineno != rte->control.DbgCtrl.curlineno) {
      return breakpoint_wait(rte, lineno);
   }

   if (rte->control.DbgCtrl.executed) {
      return breakpoint_wait(rte, lineno);
   }

   return breakpoint_go(rte);
}

#define STEPPED_OVER(rte,lineno) (((unsigned int)lineno != rte->control.DbgCtrl.curlineno) &&  \
                                 (rte->stack.top <= (int)(rte->control.DbgCtrl.calldepthsaved)))

static int CheckForDebugStepOver(rte_t* rte, int lineno)
{
   assert (rte);

   if (STEPPED_OVER(rte, lineno)) {
      return breakpoint_wait(rte, lineno);
   }
   /* not stepped over yet, in a sub routine*/
   if (!debug_find_breakpoint(rte, lineno)) {
      return breakpoint_go(rte);
   }
   /* in subroutine , and is a breakpoint*/
   if ((unsigned int) lineno != rte->control.DbgCtrl.curlineno) {
      return breakpoint_wait(rte, lineno);
   }

   if (rte->control.DbgCtrl.executed) {
      return breakpoint_wait(rte, lineno);
   }
   
   return breakpoint_go(rte);
}

static int CheckForDebugStepInto(rte_t* rte, tree_node_t* stmt)
{
   assert (rte);
   assert (stmt);

   if (stmt->type.stmt == COMPOUND_STMT) {
      return breakpoint_go(rte);
   }
   return breakpoint_wait(rte, stmt->line_no);
}

#define STEPPED_OUT(rte,lineno) (rte->stack.top < (int) (rte->control.DbgCtrl.calldepthsaved) )

static int CheckForDebugStepOut(rte_t* rte, int lineno)
{
   assert (rte);
   if (STEPPED_OUT(rte, lineno)) {
      return breakpoint_wait(rte, lineno);
   }
   /* Not stepped out yet*/
   if (!debug_find_breakpoint(rte, lineno)) {
      return breakpoint_go(rte);
   }
   /* not out yet and is breakpoint */
   if (lineno != rte->control.DbgCtrl.curlineno) {
      return breakpoint_wait(rte, lineno);
   }

   if (rte->control.DbgCtrl.executed) {
      return breakpoint_wait(rte, lineno);
   }
   
   return breakpoint_go(rte);
}

static int CheckForDebugStart(rte_t* rte, int lineno)
{
   assert (rte);
   if (debug_find_breakpoint(rte, lineno)) {
      return breakpoint_wait(rte, lineno);
   }
   return breakpoint_go(rte);;
}

static int ProcessDebugCommand (rte_t* rte, tree_node_t* stmt)
{
   assert (rte->control.Debug);
   assert (stmt);
   assert (rte);

   if (rte->control.DbgCtrl.waitfornext) {
      get_debug_cmd(rte);
      rte->control.DbgCtrl.calldepthsaved = rte->stack.top;
      rte->control.DbgCtrl.curlineno = stmt->line_no;
      if (rte->control.DbgCtrl.command == MSG_DEBUG_STEP_TO ) {
         return CheckForDebugStepTo(rte, stmt->line_no);
      } else if ( rte->control.DbgCtrl.command == MSG_DEBUG_START) {
         return CheckForDebugStart (rte, stmt->line_no);
      }
      return DEBUG_GO;
   }
   /* if waitfornext is false, then the previous command not finished yet.*/
   switch (rte->control.DbgCtrl.command) {
   case MSG_DEBUG_GO:
   case MSG_DEBUG_START:
      return CheckForDebugGo(rte, stmt);

   case MSG_DEBUG_STEP_OVER:
      return CheckForDebugStepOver(rte, stmt->line_no);

   case MSG_DEBUG_STEP_INTO:
      return CheckForDebugStepInto(rte, stmt);

   case MSG_DEBUG_STEP_OUT:
      return CheckForDebugStepOut(rte, stmt->line_no);

   case MSG_DEBUG_STEP_TO:
      return CheckForDebugStepTo(rte, stmt->line_no);

   case MSG_DEBUG_STOP:
      rte->exec->debug_cmd_ack(stmt->line_no);
      return RESULT_ABORTTED_BY_USER;

   default:
      break;
   }
   assert(0);
   return DEBUG_WAIT;
}

int exec_stmt (rte_t* rte, tree_node_t* stmt, value_t* result)
{
   assert (g_exec);
   assert (stmt);
   assert (rte);
   assert (stmt->node_type == StmtNode);

   if (get_abort(rte)) {
       return RESULT_ABORTTED_BY_USER;
   }

   if (get_debug_mode(rte)) {
      int ret; 
      do {
         ret = ProcessDebugCommand(rte, stmt);
         if (ret < 0) {
            return ret;
         }
      } while (ret == DEBUG_WAIT);
   }

   cur_lineno(rte) = stmt->line_no;
   switch (stmt->type.stmt) {
   case TOKEN_RESET:
      rte->exec->reset ();
      return 0;

   case TOKEN_WAIT:
      return exec_wait (rte, stmt);

   case TOKEN_ASSIGN:
      return exec_assign (rte, stmt);

   case TOKEN_RETURN:
      return exec_return (rte, stmt, result);

   case TOKEN_CANVASSIZE:
      return exec_cs (rte, stmt);

   case TOKEN_CANVASCOLOR :
      return exec_cc (rte, stmt);

   case TOKEN_PENCOLOR:
      return exec_pc (rte, stmt);

   case TOKEN_PENWIDTH:
      return exec_pw (rte, stmt);

   case TOKEN_GO:
      return exec_go (rte, stmt);

   case TOKEN_TURNRIGHT:
      return exec_tr (rte, stmt);

   case TOKEN_TURNLEFT:
      return exec_tl (rte, stmt);

   case TOKEN_FORWARD:
      return exec_fw (rte, stmt);

   case TOKEN_DIRECTION:
      return exec_dir (rte, stmt);

   case TOKEN_BACKWARD:
      return exec_bw (rte, stmt);

   case TOKEN_IF:
      return exec_if (rte, stmt, result);

   case COMPOUND_STMT:
      return exec_stmt_seq (rte, stmt->child[0], result);

   case ROUTINE_STMT: 
      return routine_expr (rte, stmt, result);

   case TOKEN_FOR:
      return exec_for (rte, stmt, result);

   case TOKEN_REPEAT:
      return exec_repeat (rte, stmt, result);

   case TOKEN_WHILE:
      return exec_while (rte, stmt, result);

   case TOKEN_MESSAGE:
      return exec_message (rte, stmt);

   case TOKEN_BREAK:
      return exec_break(rte, stmt);

   case TOKEN_CONTINUE:
       return exec_continue(rte, stmt);

   case TOKEN_FONTSIZE:
      return exec_fontsize (rte, stmt);

   case TOKEN_GOX:
      return exec_gox (rte, stmt);

   case TOKEN_GOY:
      return exec_goy (rte, stmt);

   case TOKEN_PRINT:
      return exec_print (rte, stmt);

   case TOKEN_HIDE:
      rte->exec->hide();
      return 0;

   case TOKEN_CLEAR:
      rte->exec->clear();
      return 0;

   case TOKEN_SHOW:
      rte->exec->show();
      return 0;

   case TOKEN_CENTER:
      rte->exec->center();
      return 0;

   case TOKEN_WRAPON:
      rte->exec->wrapon();
      return 0;

   case TOKEN_WRAPOFF:
      rte->exec->wrapoff();
      return 0;

   case TOKEN_PENUP:
      rte->exec->penup();
      return 0;

   case TOKEN_PENDOWN:
      rte->exec->pendown();
      return 0;

   default:
      assert (0);
      return -1; 
   } 
   return 0;
}

void print_value (value_t* v)
{
   assert (v);
   switch (v->type) {
   case NoneVal:
      print_info (DEBUG_INFO, "VALUE NOT INITIALIZED.");
      break;
   case NumericVal:
      print_info (DEBUG_INFO, "%g", v->val);
      break;
   case StringVal:
      print_info (DEBUG_INFO, "\"%s\" (%p)", v->str, v->str);
      break;
   default:
      assert (0);
   }
   return;
}

void print_var_list (rte_t* rte)
{
   assert (rte);

   variable_t* cur = cur_var_list(rte);

   print_info (DEBUG_INFO, "---In Routine %s: \r\n", cur_rtn(rte)->node_id);
   while (cur) {
      print_info (DEBUG_INFO, "%s\t\t\t", cur->node_id);
      print_value (&(cur->value));
      print_info (DEBUG_INFO, "\r\n");
      cur = (variable_t*) cur->next_node;
   }
}

#define CHECK_NUMERIC_EXPR(rte,expr,val,stmt_name) \
   do { \
      assert (expr); \
      assert (expr->node_type == ExpNode); \
      int ret = calc_expr (rte, expr, &val); \
      if (ret < 0) { \
         return ret; \
      }  \
      if (val.type != NumericVal) { \
         print_info (ERROR_INFO,  "%s statement need a numeric value. At line %d.", \
                  stmt_name, stmt->line_no);   \
         return -1;  \
      } \
   } while (0)

#define CHECK_STRING_EXPR(rte,expr,val,stmt_name) \
   do { \
      assert (expr); \
      assert (expr->node_type == ExpNode); \
      int ret = calc_expr (rte, expr, &val); \
      if (ret < 0) { \
         return ret; \
      }  \
      if (val.type != StringVal) { \
         print_info (ERROR_INFO, "%s statement need a string value. At line %d.", \
                  stmt_name, stmt->line_no);   \
         return -1;  \
      } \
   } while (0)

int exec_wait (rte_t* rte, tree_node_t* stmt)
{
   value_t val;

   assert (stmt);
   assert (stmt->node_type == StmtNode);
   assert (stmt->type.stmt == TOKEN_WAIT);
   assert (stmt->child[0]);
   assert (rte);
   assert (rte->rtn_lst);

   CHECK_NUMERIC_EXPR(rte, stmt->child[0], val, "Wait");
   DEBUG_CMD_INFO ("wait", &val);
#ifdef WIN32
   Sleep ((DWORD)(val.val*1000));
#else
   usleep ((useconds_t)(val.val * 1000000));
#endif /* WIN32*/
   return 0;
}

int exec_return (rte_t* rte, tree_node_t* stmt, value_t* result)
{
   int ret;

   assert (stmt);
   assert (stmt->node_type == StmtNode);
   assert (stmt->type.stmt == TOKEN_RETURN);
   assert (rte);
   assert (rte->rtn_lst);

   if (!stmt->child[0]) {
      return 1;
   }

   assert (stmt->child[0]);
   assert (stmt->child[0]->node_type == ExpNode);

   ret = calc_expr (rte, stmt->child[0], result);
   if (ret < 0) {
      return ret;
   }
   DEBUG_CMD_INFO ("return", result);
   return 1;
}

int exec_assign (rte_t* rte, tree_node_t* stmt)
{
   variable_t*       var;
   tree_node_t*      lvalue;
   tree_node_t*      rvalue;
   int               ret;
   value_t           val;
 
   assert (stmt);
   assert (stmt->node_type == StmtNode);
   assert (stmt->type.stmt == TOKEN_ASSIGN);
   assert (rte);
   assert (rte->rtn_lst);

   lvalue = stmt->child[0];
   rvalue = stmt->child[1];

   assert (lvalue && rvalue);
   assert (lvalue->node_type == ExpNode);
   assert (lvalue->type.exp == IdExp);
   assert (rvalue->node_type == ExpNode);


   ret = calc_expr (rte, rvalue, &val);
   if (ret < 0) {
      return ret;
   }
   var = (variable_t*) find_in_list ((list_node_t*)(cur_var_list(rte)),
                                     lvalue->attr.id_str);
   if (!var) {
      /* This is a new variable*/
      var = create_variable (rte, lvalue);
      (var->value).copy_value (&val);
      print_var_list (rte);
      return 0;
   }
   /* This variable exists, check type*/
   if (var->value.type != val.type) {
      print_info (ERROR_INFO, "Right value type doesn't match left value type. At line %d.",
               stmt->line_no);
      return -1;
   }
   (var->value).copy_value (&val);
   print_var_list (rte);
   return 0;
}

int exec_cs (rte_t* rte, tree_node_t* stmt)
{
   value_t x, y;

   assert (stmt);
   assert (stmt->node_type == StmtNode);
   assert (stmt->type.stmt == TOKEN_CANVASSIZE);
   assert (rte);
   assert (rte->rtn_lst);
   assert (rte->exec);

   CHECK_NUMERIC_EXPR(rte, stmt->child[0], x, "Canvassize");
   CHECK_NUMERIC_EXPR(rte, stmt->child[1], y, "Canvassize");

   rte->exec->canvassize(x.val, y.val);
   return 0;
}

int exec_cc (rte_t* rte, tree_node_t* stmt)
{
   value_t r, g, b;

   assert (stmt);
   assert (stmt->node_type == StmtNode);
   assert (stmt->type.stmt == TOKEN_CANVASCOLOR);
   assert (rte);
   assert (rte->rtn_lst);
   assert (rte->exec);

   CHECK_NUMERIC_EXPR(rte, stmt->child[0], r, "Canvascolor");
   CHECK_NUMERIC_EXPR(rte, stmt->child[1], g, "Canvascolor");
   CHECK_NUMERIC_EXPR(rte, stmt->child[2], b, "Canvascolor");

   rte->exec->canvascolor(r.val, g.val, b.val);
   return 0;
}

int exec_pc (rte_t* rte, tree_node_t* stmt)
{
   value_t r, g, b;

   assert (stmt);
   assert (stmt->node_type == StmtNode);
   assert (stmt->type.stmt == TOKEN_PENCOLOR);
   assert (rte);
   assert (rte->rtn_lst);
   assert (rte->exec);

   CHECK_NUMERIC_EXPR(rte, stmt->child[0], r, "Pencolor");
   CHECK_NUMERIC_EXPR(rte, stmt->child[1], g, "Pencolor");
   CHECK_NUMERIC_EXPR(rte, stmt->child[2], b, "Pencolor");

   rte->exec->pencolor(r.val, g.val, b.val);
   return 0;
}

int exec_if (rte_t* rte, tree_node_t* stmt, value_t* result)
{
   value_t condition;

   assert (stmt);
   assert (stmt->node_type == StmtNode);
   assert (stmt->type.stmt == TOKEN_IF);
   assert (rte);
   assert (rte->rtn_lst);
   assert (result);

   CHECK_NUMERIC_EXPR(rte, stmt->child[0], condition, "If");

   assert (stmt->child[1]);
   assert (stmt->child[1]->node_type == StmtNode);

   if (condition.val) {
      return exec_stmt (rte, stmt->child[1], result);
   } else if (stmt->child[2]) {
      assert (stmt->child[2]->node_type == StmtNode);
      return exec_stmt (rte, stmt->child[2], result);
   }
   return 0;
}

int exec_for (rte_t* rte, tree_node_t* stmt, value_t* result)
{
   variable_t*       var;
   tree_node_t*      lvalue;
   tree_node_t*      rvalue1;
   tree_node_t*      rvalue2;
   tree_node_t*      body;
   int               ret;
   value_t           val1, val2;
 
   assert (stmt);
   assert (stmt->node_type == StmtNode);
   assert (stmt->type.stmt == TOKEN_FOR);
   assert (rte);
   assert (rte->rtn_lst);

   lvalue = stmt->child[0];
   rvalue1 = stmt->child[1];
   rvalue2 = stmt->child[2];
   body = stmt->child[3];

   assert (lvalue && rvalue1 && rvalue2);
   assert (lvalue->node_type == ExpNode);
   assert (lvalue->type.exp == IdExp);
   assert (rvalue1->node_type == ExpNode);
   assert (rvalue2->node_type == ExpNode);
   assert (body->node_type == StmtNode);


   ret = calc_expr (rte, rvalue1, &val1);
   if (ret < 0) {
      return ret;
   }

   ret = calc_expr (rte, rvalue2, &val2);
   if (ret < 0) {
      return ret;
   }

   if (val1.type != NumericVal || val2.type != NumericVal) {
      print_info (ERROR_INFO, "For statement needs numeric values. At line %d.", stmt->line_no);
      return -1;
   }

   var = (variable_t*) find_in_list ((list_node_t*)(cur_var_list(rte)),
                                     lvalue->attr.id_str);
   if (!var) {
      /* This is a new variable*/
      var = create_variable (rte, lvalue);
   }
   /* This variable exists, check type*/
   if (var->value.type == StringVal) {
      print_info (ERROR_INFO, "For statement variable is not initialized as numeric. At line %d.",
               stmt->line_no);
      return -1;
   }
   (var->value).copy_value(&val1);

   assert (var->value.type == NumericVal && val1.type == NumericVal &&
           val2.type == NumericVal);

   while (var->value.val <= val2.val) {
      int ret;
      print_var_list (rte);
      ret = exec_stmt (rte, body, result);
      Sleep(0);
      if (ret == RESULT_BREAK) {
          return 0;
      } else if (ret != RESULT_CONTINUE && ret != 0 ) {
          return ret;
      }
      var->value.val += 1;
   }
   return 0;
}

int exec_repeat (rte_t* rte, tree_node_t* stmt, value_t* result)
{
   value_t n;
   int i = 0;

   assert (stmt);
   assert (stmt->node_type == StmtNode);
   assert (stmt->type.stmt == TOKEN_REPEAT);
   assert (rte);
   assert (rte->rtn_lst);
   assert (result);

   CHECK_NUMERIC_EXPR(rte, stmt->child[0], n, "Repeat");

   assert (stmt->child[1]);
   assert (stmt->child[1]->node_type == StmtNode);

   for (i = 0; i < n.val; i++) {
      int ret = exec_stmt (rte, stmt->child[1], result);
      Sleep(0);
      if (ret == RESULT_BREAK) {
          return 0;
      } else if (ret != RESULT_CONTINUE && ret != 0 ) {
          return ret;
      }
   }

   return 0;
}

int exec_while (rte_t* rte, tree_node_t* stmt, value_t* result)
{
   value_t cond;

   assert (stmt);
   assert (stmt->node_type == StmtNode);
   assert (stmt->type.stmt == TOKEN_WHILE);
   assert (rte);
   assert (rte->rtn_lst);
   assert (result);

   CHECK_NUMERIC_EXPR(rte, stmt->child[0], cond, "While");

   assert (stmt->child[1]);
   assert (stmt->child[1]->node_type == StmtNode);

   while (cond.val) {
      int ret = exec_stmt (rte, stmt->child[1], result);
      Sleep(0);
      if (ret == RESULT_BREAK) {
          return 0;
      } else if (ret != RESULT_CONTINUE && ret != 0 ) {
          return ret;
      }
      CHECK_NUMERIC_EXPR(rte, stmt->child[0], cond, "While");
   }

   return 0;
}

int exec_pw (rte_t* rte, tree_node_t* stmt)
{
   value_t width;

   assert (stmt);
   assert (stmt->node_type == StmtNode);
   assert (stmt->type.stmt == TOKEN_PENWIDTH);
   assert (rte);
   assert (rte->rtn_lst);
   assert (rte->exec);

   CHECK_NUMERIC_EXPR(rte, stmt->child[0], width, "Penwidth");

   rte->exec->penwidth(width.val);
   return 0;
}

int exec_go (rte_t* rte, tree_node_t* stmt)
{
   value_t x, y;

   assert (stmt);
   assert (stmt->node_type == StmtNode);
   assert (stmt->type.stmt == TOKEN_GO);
   assert (rte);
   assert (rte->rtn_lst);
   assert (rte->exec);

   CHECK_NUMERIC_EXPR(rte, stmt->child[0], x, "Go");
   CHECK_NUMERIC_EXPR(rte, stmt->child[1], y, "Go");

   rte->exec->go(x.val, y.val);
   return 0;
}

int exec_tr (rte_t* rte, tree_node_t* stmt)
{
   value_t angle;

   assert (stmt);
   assert (stmt->node_type == StmtNode);
   assert (stmt->type.stmt == TOKEN_TURNRIGHT);
   assert (rte);
   assert (rte->rtn_lst);
   assert (rte->exec);

   CHECK_NUMERIC_EXPR(rte, stmt->child[0], angle, "Turnright");

   rte->exec->turnright(angle.val);
   return 0;
}

int exec_tl (rte_t* rte, tree_node_t* stmt)
{
   value_t angle;

   assert (stmt);
   assert (stmt->node_type == StmtNode);
   assert (stmt->type.stmt == TOKEN_TURNLEFT);
   assert (rte);
   assert (rte->rtn_lst);
   assert (rte->exec);

   CHECK_NUMERIC_EXPR(rte, stmt->child[0], angle, "Turnright");

   rte->exec->turnleft(angle.val);
   return 0;
}

int exec_fw (rte_t* rte, tree_node_t* stmt)
{
   value_t distance;

   assert (stmt);
   assert (stmt->node_type == StmtNode);
   assert (stmt->type.stmt == TOKEN_FORWARD);
   assert (rte);
   assert (rte->rtn_lst);
   assert (rte->exec);

   CHECK_NUMERIC_EXPR(rte, stmt->child[0], distance, "Forward");

   rte->exec->forward(distance.val);
   return 0;
}

int exec_dir (rte_t* rte, tree_node_t* stmt)
{
   value_t angle;

   assert (stmt);
   assert (stmt->node_type == StmtNode);
   assert (stmt->type.stmt == TOKEN_DIRECTION);
   assert (rte);
   assert (rte->rtn_lst);
   assert (rte->exec);

   CHECK_NUMERIC_EXPR(rte, stmt->child[0], angle, "Direction");

   rte->exec->direction(angle.val);
   return 0;
}

int exec_bw (rte_t* rte, tree_node_t* stmt)
{
   value_t distance;

   assert (stmt);
   assert (stmt->node_type == StmtNode);
   assert (stmt->type.stmt == TOKEN_BACKWARD);
   assert (rte);
   assert (rte->rtn_lst);
   assert (rte->exec);

   CHECK_NUMERIC_EXPR(rte, stmt->child[0], distance, "Forward");

   rte->exec->backward(distance.val);
   return 0;
}

int exec_message (rte_t* rte, tree_node_t* stmt)
{
   value_t txt;

   assert (stmt);
   assert (stmt->node_type == StmtNode);
   assert (stmt->type.stmt == TOKEN_MESSAGE);
   assert (rte);
   assert (rte->rtn_lst);
   assert (rte->exec);

   CHECK_STRING_EXPR(rte, stmt->child[0], txt, "Message");

   rte->exec->message(txt.str);
   return 0;
}

int exec_fontsize (rte_t* rte, tree_node_t* stmt)
{
   value_t size;

   assert (stmt);
   assert (stmt->node_type == StmtNode);
   assert (stmt->type.stmt == TOKEN_FONTSIZE);
   assert (rte);
   assert (rte->rtn_lst);
   assert (rte->exec);

   CHECK_NUMERIC_EXPR(rte, stmt->child[0], size, "Fontsize");

   rte->exec->fontsize(size.val);
   return 0;
}

int exec_gox (rte_t* rte, tree_node_t* stmt)
{
   value_t x;

   assert (stmt);
   assert (stmt->node_type == StmtNode);
   assert (stmt->type.stmt == TOKEN_GOX);
   assert (rte);
   assert (rte->rtn_lst);
   assert (rte->exec);

   CHECK_NUMERIC_EXPR(rte, stmt->child[0], x, "Gox");

   rte->exec->gox(x.val);
   return 0;
}

int exec_goy (rte_t* rte, tree_node_t* stmt)
{
   value_t y;

   assert (stmt);
   assert (stmt->node_type == StmtNode);
   assert (stmt->type.stmt == TOKEN_GOY);
   assert (rte);
   assert (rte->rtn_lst);
   assert (rte->exec);

   CHECK_NUMERIC_EXPR(rte, stmt->child[0], y, "Goy");

   rte->exec->goy(y.val);
   return 0;
}

#define BUF_SIZE 1024

int exec_print (rte_t* rte, tree_node_t* stmt)
{
   tree_node_t* para;
   value_t v;
   char buf[BUF_SIZE];

   assert (stmt);
   assert (stmt->node_type == StmtNode);
   assert (stmt->type.stmt == TOKEN_PRINT);
   assert (rte);
   assert (rte->rtn_lst);
   assert (rte->exec);

   para = stmt->child[0];
   buf[0] = '\0';
   while (para) {
      char tmpbuf[BUF_SIZE];
      int ret = calc_expr (rte, para, &v); 
      if (ret < 0) { 
         return ret; 
      }
      assert (v.type != NoneVal);

      if (v.type == NumericVal) {
         snprintf (tmpbuf, sizeof(buf), "%g", v.val);
      } else if (v.type == StringVal) {
         snprintf (tmpbuf, sizeof(buf), "%s", v.str);
      }
      assert (strlen(buf) < BUF_SIZE-1);
      strncat (buf, tmpbuf, (BUF_SIZE-strlen(buf)-1) );
      para = para->sibling;
   }
   rte->exec->print(buf);
   return 0;
}

int exec_break (rte_t* rte, tree_node_t* stmt)
{
   assert (rte);
   rte->break_continue_line_no = stmt->line_no;
   return RESULT_BREAK;
}

int exec_continue (rte_t* rte, tree_node_t* stmt)
{
   assert (rte);
   rte->break_continue_line_no = stmt->line_no;
   return RESULT_CONTINUE;
}
